//
// Created by root on 2020/4/4.
//

#include <sstream>
#include <muduo/base/Logging.h>

#include "PackHandle.h"
#include "UserMgr.h"
#include "RoomMgr.h"
#include "ProtocolNoDefine.h"
#include "MakePacket.h"
#include "CommonFunction.h"

CPackHandle::CPackHandle() {
    m_hashCommand[PROTO_LOGIN] = std::bind(&CPackHandle::_HandleLogin, this, std::placeholders::_1,
            std::placeholders::_2);
    m_hashCommand[PROTO_HEARTBEAT] = std::bind(&CPackHandle::_HeartbeatPack, this, std::placeholders::_1,
            std::placeholders::_2);
    m_hashCommand[PROTO_ONLINE_LIST] = std::bind(&CPackHandle::_HandleOnlineUser, this, std::placeholders::_1,
            std::placeholders::_2);
//    m_hashCommand[PROTO_CHAT_WITH] = std::bind(&CPackHandle::_HandleCreateChat, this, std::placeholders::_1,
//            std::placeholders::_2);
    m_hashCommand[PROTO_CHAT_MSG_FORWARD] = std::bind(&CPackHandle::_HandleForwardMsg, this, std::placeholders::_1,
            std::placeholders::_2);
//    m_hashCommand[PROTO_CHAT_terminal] = std::bind(&CPackHandle::_HandleConnTerminal, this, std::placeholders::_1,
//            std::placeholders::_2);
    m_hashCommand[PROTO_QUIT] = std::bind(&CPackHandle::_HandleQuit, this,
            std::placeholders::_1, std::placeholders::_2);
}

CPackHandle::~CPackHandle() {

}

void CPackHandle::HandleCommand(TcpConnectionWeakPtr _pConn, int _iProtocolNo, const std::string& _csMessageBody) {
    nlohmann::json oJson = nlohmann::json::parse(_csMessageBody);
    int iCommand = oJson.at("protocol_id").get<int>();
    if (m_hashCommand.find(_iProtocolNo) != m_hashCommand.end())
    {
        m_hashCommand[_iProtocolNo](_pConn, oJson);
    }
    else{
        LOG_INFO << "recieve invalid protocol id:" << iCommand;
    }
}

void CPackHandle::_HandleOnlineUser(TcpConnectionWeakPtr _pConn, nlohmann::json &_jsonMsg) {
    if (muduo::net::TcpConnectionPtr pConn = _pConn.lock(); pConn)
    {
        std::vector<std::string> vtUserNames = muduo::Singleton<CUserMgr>::instance().GetAllUserName();
        auto iter = std::find_if(vtUserNames.begin(), vtUserNames.end(),
                                 [&pConn](const std::string &_sIndex){
                                     return _sIndex == pConn->name();
                                 });

        if (iter != vtUserNames.end())
        {
            vtUserNames.erase(iter);
        }

        std::ostringstream OStrStream;
        int i = 1;
        for (const auto &index : vtUserNames)
        {
            OStrStream << i << ":    " << index << std::endl;
            i++;
        }

        std::string sResult = OStrStream.str();
        sResult = sResult.size() == 0 ? "List is empty" : sResult;
        gUserMgr::instance().Send(pConn->name(), PROTO_ONLINE_LIST, sResult);
    }

}

void CPackHandle::_HandleCreateChat(TcpConnectionWeakPtr _pConn, nlohmann::json &_jsonMsg) {
//    /**
//     * chat_client_id: 目标聊天对象
//     */
//    std::string sChatClientId = _jsonMsg["chat_client_id"];
//
//    do{
//        if (sChatClientId.size() > 0)
//        {
//            if (gUserMgr::instance().IsValid(sChatClientId))
//            {
//                std::ostringstream OStrStream;
//                OStrStream << "Create Room between " << sChatClientId << " And " << _sConnId;
//
//                gRoomMgr::instance().CreateRoom(sChatClientId, _sConnId);
//                gUserMgr::instance().Send(sChatClientId, OStrStream.str());
//                gUserMgr::instance().Send(_sConnId, OStrStream.str());
//                return;
//            }
//        }
//    }while(false);
//
//    std::string sError = "Chat object is unconnected！";
//    gUserMgr::instance().Send(_sConnId, sError);
}

void CPackHandle::_HandleRemoveChat(TcpConnectionWeakPtr _pConn, nlohmann::json &_jsonMsg) {
//    /**
//     * chat_client_id : 聊天对象
//     */
//     std::string sChatClientId = _jsonMsg["chat_client_id"];
//     if (gRoomMgr::instance().IsContain(_sConnId, sChatClientId))
//     {
//         gRoomMgr::instance().CloseRoom(_sConnId, sChatClientId);
//         nlohmann::json jsonResponse;
//         jsonResponse["protocol_id"] = 100; // 删除通知协议
//         jsonResponse["chat_client_send_id"] = _sConnId;
//         jsonResponse["chat_client_recieve_id"] = sChatClientId;
//         gUserMgr::instance().Send(sChatClientId, jsonResponse.dump());
//     }
}

void CPackHandle::_HandleForwardMsg(TcpConnectionWeakPtr _pConn, nlohmann::json &_jsonMsg) {
    if (muduo::net::TcpConnectionPtr pConn = _pConn.lock(); pConn)
    {
        /**
        * receiver_id：接受端id
        * send_msg: 发送的信息
        * **/
        std::string sReceiverId = _jsonMsg["receiver_id"];
        std::string sChatMsg = _jsonMsg["send_msg"];
        if (gUserMgr::instance().IsValid(sReceiverId))
        {
            nlohmann::json jsonReponse;
            jsonReponse["send_id"] = pConn->name();
            jsonReponse["msg"] = sChatMsg;
            gUserMgr::instance().Send(sReceiverId, PROTO_CHAT_MSG_FORWARD, jsonReponse.dump());
        }
        else{
            return;
        }
    }
}

void CPackHandle::_HandleConnTerminal(TcpConnectionWeakPtr _pConn, nlohmann::json &_jsonMsg) {

}

void CPackHandle::_HandleLogin(TcpConnectionWeakPtr _pConn, nlohmann::json &_jsonMsg) {
    if (muduo::net::TcpConnectionPtr pConn = _pConn.lock(); pConn)
    {
        CUser oUser(pConn, pConn->name());
        gUserMgr::instance().Insert(oUser);

        nlohmann::json jsonReponse;
        jsonReponse["result"] = 0;      // 0:登陆成功 1:登陆失败
        gUserMgr::instance().Send(pConn->name(), PROTO_LOGIN, jsonReponse.dump());
    }
}

void CPackHandle::_HandleQuit(TcpConnectionWeakPtr _pConn, nlohmann::json &_jsonMsg) {
    if (muduo::net::TcpConnectionPtr pConn = _pConn.lock(); pConn)
    {
        gUserMgr::instance().UpdateRegular(pConn->name());
        nlohmann::json jsonReponse;
        jsonReponse["time"] = commonfunction::GetCurrentTimestamp();
        gUserMgr::instance().Send(pConn->name(),  PROTO_QUIT, jsonReponse.dump());
    }
}

void CPackHandle::_HeartbeatPack(TcpConnectionWeakPtr _pConn, nlohmann::json &_jsonMsg) {
    if (muduo::net::TcpConnectionPtr pConn = _pConn.lock(); pConn)
    {
        gUserMgr::instance().UpdateRegular(pConn->name());
        nlohmann::json jsonReponse;
        jsonReponse["time"] = commonfunction::GetCurrentTimestamp();
        gUserMgr::instance().Send(pConn->name(), PROTO_HEARTBEAT, jsonReponse.dump());
    }
}
